//
// ***********************************************
// *    ___________   ___________  __      __    *
// *   |______  __/  /_____  ___/  \ \    / /    *
// *         / /          / /       \ \  / /     *
// *        / /          / /         \ \/ /      *
// *       / /          / /           \  /       *
// *      / /______    / /            / /        *
// *     /________/   /_/            /_/         *
// *                                             *
// ***********************************************
//
//  DTSDKWebView.m
//  DTSDK
//
//  Created by wanmeizty on 6/3/19.
//  Copyright © 2019年 wanmeizty. All rights reserved.
//

#import "DTSDKWebView.h"
#import "DTJSBUtil.h"
#import "DTCallInfo.h"
#import "DTInternalApis.h"
#import <objc/message.h>

#import "ZTYTools.h"


#define STRINGISEMPTY(string) (string==nil || [string isEqual:[NSNull null]] || [string isEqualToString:@""])

@interface DTSDKJsApi ()
{
    NSInteger _SDKVersion;
}

@end

@implementation DTSDKJsApi

- (instancetype)init
{
    self = [super init];
    if (self) {
        _SDKVersion = 1030;
    }
    return self;
}

- (NSString *) testSyn: (NSString *) msg
{
    return [msg stringByAppendingString:@"[ syn call]"];
}

- (void) testAsyn:(NSString *) msg :(JSCallback) completionHandler
{
    completionHandler([msg stringByAppendingString:@" [ asyn call]"],YES);
}

// 点击 H5 返回按钮
-(void)goBack:(NSString *)msg{
    NSLog(@"goBack==%@",msg);
    if ([self.delegate respondsToSelector:@selector(goBack)]) {
        [self.delegate goBack];
    }
}

// token 失效
- ( void )tokenFail:(NSDictionary *) args :(JSCallback)completionHandler{
    
    if ([self.delegate respondsToSelector:@selector(tokenFailed:)]) {
        [self.delegate tokenFailed:args];
    }
    
}

// 跳转流量主客户端赚金币页面，无需传参。需要流量主客户端实现部分代码
-(void)earnGold:(NSString *)msg{
    if ([self.delegate respondsToSelector:@selector(earnGold)]) {
        [self.delegate earnGold];
    }
    
}

// 用户赚金币按钮是否可用，无需传参。默认不可用
-(BOOL)getEarnGoldStatus:(NSString *)msg{
    return NO;
}

// 金币兑换淘礼金成功后回调， 无需传参
-(void)consumeSuccess:(NSString *)msg{
    if ([self.delegate respondsToSelector:@selector(consumeSuccess)]) {
        [self.delegate consumeSuccess];
    }
}

// scheme跳转到淘宝进行购物，参数为json
-(BOOL)openSchemeInApp:(NSDictionary *)args{
    NSString * scheme = [args objectForKey:@"scheme"];
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:scheme]]) {
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:scheme]];
        return YES;
    }else{
        [ZTYTools showMessage:@"当前设备未安装手机淘宝，请安装后再重试一下"];
        return NO;
    }
}

// 客户端传的金币和金额返回给前端，无需传参。暂时弃用
-(NSString *)getAccountInfo:(NSString *)msg{
    
    return @"";
}

// 获取设备信息，无需传参。
-(NSString *)getDeviceInfo:(NSString *)msg{
    // 获取设备信息
    return [ZTYTools getPhoneInfoString];
}


// 获取设备IMEI号，无需传参。 需要设备权限
-(NSString *)getDeviceIMEI:(NSString *)msg{
    
    return [ZTYTools getDeviceImei];
}


// 判断手机是否安装了前端传来的包名，并把安装结果返回给前端。
-(BOOL)isAppInstall:(NSString *)packageName{
    
    NSLog(@"%@",packageName);
    NSString * appSckeme = @"";
    if ([packageName containsString:@"taobao"] || [packageName containsString:@"tbopen"] || [packageName containsString:@"tmall"]) {
        appSckeme = @"taobao://";
    }else if ([packageName containsString:@"jd"]||[packageName containsString:@"jindong"]){
        appSckeme = @"openapp.jdmobile://";
    }else if ([packageName containsString:@"pinduoduo"]){
        appSckeme = @"pinduoduo://";
    }else if ([packageName containsString:@"com.tencent.mm"]){
        appSckeme = @"wechat://";
    }else{
        appSckeme = packageName;
    }
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:appSckeme]]) {
        NSLog(@"安装");
        return YES;
    }else{
        NSLog(@"未安装");
        return NO;
    }
    
    return YES;
}

-(void)evokeApp:(NSString *)sckeme{
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:sckeme]]) {
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:sckeme]];
    }
}

// 获取 SDK 版本号
- (NSString *)getSDKVersion:(NSString *)msg{
    
    [ZTYTools sharedTools].sdkVersion = _SDKVersion;
    return [NSString stringWithFormat:@"%ld",_SDKVersion];
}

#pragma brage
// 获取 App 版本号
- (NSString *)getAppVersion:(NSString *)msg{
    //app版本相关
    NSString * appVersion = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBundleShortVersionString"];
    return appVersion;
}

//版本1020
//统一的网络请求方法，可用于获取淘宝商品详情，参数为需要请求的url， 异步调用
-(void)commonRequestNetwork:(NSString *)args :(JSCallback)completionHandler{
    NSLog(@"args===>%@",args);
    NSString * url = args;
    //    if ([url containsString:@"{"] ||[url containsString:@"}"]) {
    //        NSArray * comparesArr = [url componentsSeparatedByString:@"="];
    //        NSString * decodeStr = [self URLDecodedStringWithEncodedStr:comparesArr[1]];
    //        NSString * encodeStr = [self urlEncodeStr:decodeStr];
    //        url = [NSString stringWithFormat:@"%@=%@",comparesArr[0],encodeStr];
    //    }
    
    if ([url containsString:@"{"])url = [url stringByReplacingOccurrencesOfString:@"{" withString:@"%7B"];
    
    if ([url containsString:@"}"]) url = [url stringByReplacingOccurrencesOfString:@"}" withString:@"%7D"];
    if ([url containsString:@"\""]) url = [url stringByReplacingOccurrencesOfString:@"\"" withString:@"%22"];
    
    
    url = [url stringByReplacingOccurrencesOfString:@"\r\n" withString:@""];
    url = [url stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    url = [url stringByReplacingOccurrencesOfString:@"\t" withString:@""];

    NSURL *zoneUrl = [NSURL URLWithString:url];
    NSError * err = nil;
    NSString *zoneStr = [NSString stringWithContentsOfURL:zoneUrl encoding:NSUTF8StringEncoding error:&err];
    if (err == nil) {
        completionHandler(zoneStr,YES);
    }else{
        completionHandler(@"",YES);
    }
}


// 版本1030
// 商品解析，获取正品保障等字段。参数为商品ID，异步调用
-(void)analyzeTbGoods:(NSString *)args{
    if ([self.delegate respondsToSelector:@selector(analyzeTbGoods:)]) {
        [self.delegate analyzeTbGoods:args];
    }
}

/**
 * 设置SDK版本
 * @param version SDK版本
 **/
-(void)setUpSDKVersion:(NSInteger)version{
    _SDKVersion = version;
}

@end


typedef void (^JSCallback)(NSString * _Nullable result,BOOL complete);


@interface DTSDKWebView () <WKUIDelegate>

//@property (copy,nonatomic) void(^gobackBlock)(void);


- (void)loadUrl: (NSString * _Nonnull) url;

// Call javascript handler
-(void) callHandler:(NSString * _Nonnull) methodName  arguments:(NSArray * _Nullable) args;
-(void) callHandler:(NSString * _Nonnull) methodName  completionHandler:(void (^ _Nullable)(id _Nullable value))completionHandler;
-(void) callHandler:(NSString * _Nonnull) methodName  arguments:(NSArray * _Nullable) args completionHandler:(void (^ _Nullable)(id _Nullable value))completionHandler;

// set a listener for javascript closing the current page.
- (void)setJavascriptCloseWindowListener:(void(^_Nullable)(void))callback;

/**
 * Add a Javascript Object to dsBridge with namespace.
 * @param object
 * which implemented the javascript interfaces
 * @param namespace
 * if empty, the object have no namespace.
 **/
- (void)addJavascriptObject:(id _Nullable ) object namespace:(NSString *  _Nullable) namespace;

//// Remove the Javascript Object with the supplied namespace
//- (void)removeJavascriptObject:(NSString *  _Nullable) namespace;

// Test whether the handler exist in javascript
- (void) hasJavascriptMethod:(NSString * _Nonnull) handlerName methodExistCallback:(void(^ _Nullable)(bool exist))callback;

// Set debug mode. if in debug mode, some errors will be prompted by a dialog
// and the exception caused by the native handlers will not be captured.
- (void) setDebugMode:(bool) debug;

- (void) disableJavascriptDialogBlock:(bool) disable;

// custom the  label text of  javascript dialog that includes alert/confirm/prompt
- (void) customJavascriptDialogLabelTitles:(NSDictionary*_Nullable) dic;

// private method, the developer shoudn't call this method
- (id _Nullable ) onMessage:(NSDictionary *_Nonnull) msg type:(int) type;

@end

@interface DTSDKWebView ()
//@property (strong,nonatomic) WKWebView *jumpweb;
@end

@implementation DTSDKWebView
{
    void (^alertHandler)(void);
    void (^confirmHandler)(BOOL);
    void (^promptHandler)(NSString *);
    void(^javascriptCloseWindowListener)(void);
    int dialogType;
    int callId;
    bool jsDialogBlock;
    NSMutableDictionary<NSString *,id> *javaScriptNamespaceInterfaces;
    NSMutableDictionary *handerMap;
    NSMutableArray<DTCallInfo *> * callInfoList;
    NSDictionary<NSString*,NSString*> *dialogTextDic;
    UITextField *txtName;
    UInt64 lastCallTime ;
    NSString *jsCache;
    bool isPending;
    bool isDebug;
}

-(instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
{
    txtName=nil;
    dialogType=0;
    callId=0;
    alertHandler=nil;
    confirmHandler=nil;
    promptHandler=nil;
    jsDialogBlock=true;
    callInfoList=[NSMutableArray array];
    javaScriptNamespaceInterfaces=[NSMutableDictionary dictionary];
    handerMap=[NSMutableDictionary dictionary];
    lastCallTime = 0;
    jsCache=@"";
    isPending=false;
    isDebug=false;
    dialogTextDic=@{};
    // document.cookie ='TeskWKCookieKey1=TeskWKCookieValue1';document.cookie = 'TeskWKCookieKey2=TeskWKCookieValue2';
    
    WKUserScript *script = [[WKUserScript alloc] initWithSource:[NSString stringWithFormat:@"window._dswk=true;"] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
    [configuration.userContentController addUserScript:script];
    
    
//    configuration.processPool = [WKProcessPool sharedProcessPool];

    self = [super initWithFrame:frame configuration: configuration];
    if (self) {
        super.UIDelegate=self;
    }
    // add internal Javascript Object
    DTInternalApis *  interalApis= [[DTInternalApis alloc] init];
    interalApis.webview=self;
    [self addJavascriptObject:interalApis namespace:@"_dsb"];
    return self;
}


-(instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration cookieStr:(NSString *)cookiestr
{
    txtName=nil;
    dialogType=0;
    callId=0;
    alertHandler=nil;
    confirmHandler=nil;
    promptHandler=nil;
    jsDialogBlock=true;
    callInfoList=[NSMutableArray array];
    javaScriptNamespaceInterfaces=[NSMutableDictionary dictionary];
    handerMap=[NSMutableDictionary dictionary];
    lastCallTime = 0;
    jsCache=@"";
    isPending=false;
    isDebug=false;
    dialogTextDic=@{};
    // document.cookie ='TeskWKCookieKey1=TeskWKCookieValue1';document.cookie = 'TeskWKCookieKey2=TeskWKCookieValue2';
    
    WKUserScript *script = [[WKUserScript alloc] initWithSource:[NSString stringWithFormat:@"window._dswk=true;%@",cookiestr] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
    [configuration.userContentController addUserScript:script];
    
    self = [super initWithFrame:frame configuration: configuration];
    if (self) {
        super.UIDelegate=self;
    }
    // add internal Javascript Object
    DTInternalApis *  interalApis= [[DTInternalApis alloc] init];
    interalApis.webview=self;
    [self addJavascriptObject:interalApis namespace:@"_dsb"];
    return self;
}

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt
    defaultText:(nullable NSString *)defaultText
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(NSString * _Nullable result))completionHandler
{
    NSString * prefix=@"_dsbridge=";
    if ([prompt hasPrefix:prefix])
    {
        NSString *method= [prompt substringFromIndex:[prefix length]];
        NSString *result=nil;
        if(isDebug){
            result =[self call:method :defaultText ];
        }else{
            @try {
                result =[self call:method :defaultText ];
            }@catch(NSException *exception){
                NSLog(@"%@", exception);
            }
        }
        completionHandler(result);
        
    }else {
        if(!jsDialogBlock){
            completionHandler(nil);
        }
        if(self.DSUIDelegate && [self.DSUIDelegate respondsToSelector:
                                 @selector(webView:runJavaScriptTextInputPanelWithPrompt
                                           :defaultText:initiatedByFrame
                                           :completionHandler:)])
        {
            return [self.DSUIDelegate webView:webView runJavaScriptTextInputPanelWithPrompt:prompt
                                  defaultText:defaultText
                             initiatedByFrame:frame
                            completionHandler:completionHandler];
        }else{
            dialogType=3;
            if(jsDialogBlock){
                promptHandler=completionHandler;
            }
            UIAlertView *alert = [[UIAlertView alloc]
                                  initWithTitle:prompt
                                  message:@""
                                  delegate:self
                                  cancelButtonTitle:dialogTextDic[@"promptCancelBtn"]?dialogTextDic[@"promptCancelBtn"]:@"取消"
                                  otherButtonTitles:dialogTextDic[@"promptOkBtn"]?dialogTextDic[@"promptOkBtn"]:@"确定",
                                  nil];
            [alert setAlertViewStyle:UIAlertViewStylePlainTextInput];
            txtName = [alert textFieldAtIndex:0];
            txtName.text=defaultText;
            [alert show];
        }
    }
}

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(void))completionHandler
{
    if(!jsDialogBlock){
        completionHandler();
    }
    if( self.DSUIDelegate &&  [self.DSUIDelegate respondsToSelector:
                               @selector(webView:runJavaScriptAlertPanelWithMessage
                                         :initiatedByFrame:completionHandler:)])
    {
        return [self.DSUIDelegate webView:webView runJavaScriptAlertPanelWithMessage:message
                         initiatedByFrame:frame
                        completionHandler:completionHandler];
    }else{
        dialogType=1;
        if(jsDialogBlock){
            alertHandler=completionHandler;
        }
        UIAlertView *alertView =
        [[UIAlertView alloc] initWithTitle:dialogTextDic[@"alertTitle"]?dialogTextDic[@"alertTitle"]:@"提示"
                                   message:message
                                  delegate:self
                         cancelButtonTitle:dialogTextDic[@"alertBtn"]?dialogTextDic[@"alertBtn"]:@"确定"
                         otherButtonTitles:nil,nil];
        [alertView show];
    }
}

-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler
{
    if(!jsDialogBlock){
        completionHandler(YES);
    }
    if( self.DSUIDelegate&& [self.DSUIDelegate respondsToSelector:
                             @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)])
    {
        return[self.DSUIDelegate webView:webView runJavaScriptConfirmPanelWithMessage:message
                        initiatedByFrame:frame
                       completionHandler:completionHandler];
    }else{
        dialogType=2;
        if(jsDialogBlock){
            confirmHandler=completionHandler;
        }
        UIAlertView *alertView =
        [[UIAlertView alloc] initWithTitle:dialogTextDic[@"confirmTitle"]?dialogTextDic[@"confirmTitle"]:@"提示"
                                   message:message
                                  delegate:self
                         cancelButtonTitle:dialogTextDic[@"confirmCancelBtn"]?dialogTextDic[@"confirmCancelBtn"]:@"取消"
                         otherButtonTitles:dialogTextDic[@"confirmOkBtn"]?dialogTextDic[@"confirmOkBtn"]:@"确定", nil];
        [alertView show];
    }
}

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
    if( self.DSUIDelegate && [self.DSUIDelegate respondsToSelector:
                              @selector(webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:)]){
        return [self.DSUIDelegate webView:webView createWebViewWithConfiguration:configuration forNavigationAction:navigationAction windowFeatures:windowFeatures];
    }
    return  nil;
}

- (void)webViewDidClose:(WKWebView *)webView{
    if( self.DSUIDelegate && [self.DSUIDelegate respondsToSelector:
                              @selector(webViewDidClose:)]){
        [self.DSUIDelegate webViewDidClose:webView];
    }
}

- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo{
    if( self.DSUIDelegate
       && [self.DSUIDelegate respondsToSelector:
           @selector(webView:shouldPreviewElement:)]){
           return [self.DSUIDelegate webView:webView shouldPreviewElement:elementInfo];
       }
    return NO;
}

- (UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray<id<WKPreviewActionItem>> *)previewActions{
    if( self.DSUIDelegate &&
       [self.DSUIDelegate respondsToSelector:@selector(webView:previewingViewControllerForElement:defaultActions:)]){
        return [self.DSUIDelegate
                webView:webView
                previewingViewControllerForElement:elementInfo
                defaultActions:previewActions
                ];
    }
    return  nil;
}


- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController{
    if( self.DSUIDelegate
       && [self.DSUIDelegate respondsToSelector:@selector(webView:commitPreviewingViewController:)]){
        return [self.DSUIDelegate webView:webView commitPreviewingViewController:previewingViewController];
    }
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if(dialogType==1 && alertHandler){
        alertHandler();
        alertHandler=nil;
    }else if(dialogType==2 && confirmHandler){
        confirmHandler(buttonIndex==1?YES:NO);
        confirmHandler=nil;
    }else if(dialogType==3 && promptHandler && txtName) {
        if(buttonIndex==1){
            promptHandler([txtName text]);
        }else{
            promptHandler(@"");
        }
        promptHandler=nil;
        txtName=nil;
    }
}

- (void) evalJavascript:(int) delay{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
        @synchronized(self){
            if([jsCache length]!=0){
                [self evaluateJavaScript :jsCache completionHandler:nil];
                isPending=false;
                jsCache=@"";
                lastCallTime=[[NSDate date] timeIntervalSince1970]*1000;
            }
        }
    });
}

-(NSString *)call:(NSString*) method :(NSString*) argStr
{
    NSArray *nameStr=[DTJSBUtil parseNamespace:[method stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
    
    id JavascriptInterfaceObject=javaScriptNamespaceInterfaces[nameStr[0]];
    NSString *error=[NSString stringWithFormat:@"Error! \n Method %@ is not invoked, since there is not a implementation for it",method];
    NSMutableDictionary*result =[NSMutableDictionary dictionaryWithDictionary:@{@"code":@-1,@"data":@""}];
    if(!JavascriptInterfaceObject){
        NSLog(@"Js bridge  called, but can't find a corresponded JavascriptObject , please check your code!");
    }else{
        method=nameStr[1];
        NSString *methodOne = [DTJSBUtil methodByNameArg:1 selName:method class:[JavascriptInterfaceObject class]];
        NSString *methodTwo = [DTJSBUtil methodByNameArg:2 selName:method class:[JavascriptInterfaceObject class]];
        SEL sel=NSSelectorFromString(methodOne);
        SEL selasyn=NSSelectorFromString(methodTwo);
        NSDictionary * args=[DTJSBUtil jsonStringToObject:argStr];
        id arg=args[@"data"];
        if(arg==[NSNull null]){
            arg=nil;
        }
        NSString * cb;
        do{
            if(args && (cb= args[@"_dscbstub"])){
                if([JavascriptInterfaceObject respondsToSelector:selasyn]){
                    __weak typeof(self) weakSelf = self;
                    void (^completionHandler)(id,BOOL) = ^(id value,BOOL complete){
                        NSString *del=@"";
                        result[@"code"]=@0;
                        if(value!=nil){
                            result[@"data"]=value;
                        }
                        value=[DTJSBUtil objToJsonString:result];
                        value=[value stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
                        
                        if(complete){
                            del=[@"delete window." stringByAppendingString:cb];
                        }
                        NSString*js=[NSString stringWithFormat:@"try {%@(JSON.parse(decodeURIComponent(\"%@\")).data);%@; } catch(e){};",cb,(value == nil) ? @"" : value,del];
                        __strong typeof(self) strongSelf = weakSelf;
                        @synchronized(self)
                        {
                            UInt64  t=[[NSDate date] timeIntervalSince1970]*1000;
                            jsCache=[jsCache stringByAppendingString:js];
                            if(t-lastCallTime<50){
                                if(!isPending){
                                    [strongSelf evalJavascript:50];
                                    isPending=true;
                                }
                            }else{
                                [strongSelf evalJavascript:0];
                            }
                        }
                        
                    };
                    
                    void(*action)(id,SEL,id,id) = (void(*)(id,SEL,id,id))objc_msgSend;
                    action(JavascriptInterfaceObject,selasyn,arg,completionHandler);
                    break;
                }
            }else if([JavascriptInterfaceObject respondsToSelector:sel]){
                id ret;
                id(*action)(id,SEL,id) = (id(*)(id,SEL,id))objc_msgSend;
                
                
                // 如下针对返回BOOL类型赋值野指针问题
                // 判断返回值类型
                Method method = class_getInstanceMethod([JavascriptInterfaceObject class], sel);
                char retType[512] = {};
                method_getReturnType(method, retType, 512);
//                NSLog(@"返回类型值类型:%s",retType);
                if (strcmp(retType, "B") == 0) {
                    // 解决BOOL值返回问题
                    //ios8下特殊写法
                    BOOL a = ((BOOL(*)(id,SEL, id,id))objc_msgSend)(JavascriptInterfaceObject, sel, arg,nil);
                    ret = @(a);
                    
                }else if (strcmp(retType, "v") == 0){
                    ret = nil;
                    ((void(*)(id,SEL, id,id))objc_msgSend)(JavascriptInterfaceObject, sel, arg,nil);
//                    action(JavascriptInterfaceObject,sel,arg);
                }else{
                    ret=action(JavascriptInterfaceObject,sel,arg);
                }
//                ret=action(JavascriptInterfaceObject,sel,arg);
                [result setValue:@0 forKey:@"code"];
                if(ret!=nil){
                    [result setValue:ret forKey:@"data"];
                }
                break;
            }
            NSString*js=[error stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
            if(isDebug){
                js=[NSString stringWithFormat:@"window.alert(decodeURIComponent(\"%@\"));",js];
                [self evaluateJavaScript :js completionHandler:nil];
            }
            NSLog(@"%@",error);
        }while (0);
    }
    return [DTJSBUtil objToJsonString:result];
}

- (void)setJavascriptCloseWindowListener:(void (^)(void))callback
{
    javascriptCloseWindowListener=callback;
}

- (void)setDebugMode:(bool)debug{
    
    isDebug=debug;
}

- (void)loadUrl: (NSString *)url
{
    
//    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
//    NSMutableDictionary *cookieDic = [NSMutableDictionary dictionary];
//
//    NSMutableString *cookieValue = [NSMutableString stringWithFormat:@""];
//    NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
//
//    for (NSHTTPCookie *cookie in [cookieJar cookies]) {
//        [cookieDic setObject:cookie.value forKey:cookie.name];
//    }
//
//    // cookie重复，先放到字典进行去重，再进行拼接
//    for (NSString *key in cookieDic) {
//        NSString *appendString = [NSString stringWithFormat:@"%@=%@;", key, [cookieDic valueForKey:key]];
//        [cookieValue appendString:appendString];
//    }
//
//    [request addValue:cookieValue forHTTPHeaderField:@"Cookie"];
    NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    [self loadRequest:request];
}

- (void)callHandler:(NSString *)methodName arguments:(NSArray *)args{
    [self callHandler:methodName arguments:args completionHandler:nil];
}

- (void)callHandler:(NSString *)methodName completionHandler:(void (^)(id _Nullable))completionHandler{
    [self callHandler:methodName arguments:nil completionHandler:completionHandler];
}

-(void)callHandler:(NSString *)methodName arguments:(NSArray *)args completionHandler:(void (^)(id  _Nullable value))completionHandler
{
    DTCallInfo *callInfo=[[DTCallInfo alloc] init];
    callInfo.id=[NSNumber numberWithInt: callId++];
    callInfo.args=args==nil?@[]:args;
    callInfo.method=methodName;
    if(completionHandler){
        [handerMap setObject:completionHandler forKey:callInfo.id];
    }
    if(callInfoList!=nil){
        [callInfoList addObject:callInfo];
    }else{
        [self dispatchJavascriptCall:callInfo];
    }
}

- (void)dispatchStartupQueue{
    if(callInfoList==nil) return;
    for (DTCallInfo * callInfo in callInfoList) {
        [self dispatchJavascriptCall:callInfo];
    }
    callInfoList=nil;
}

- (void) dispatchJavascriptCall:(DTCallInfo*) info{
    NSString * json=[DTJSBUtil objToJsonString:@{@"method":info.method,@"callbackId":info.id,
                                               @"data":[DTJSBUtil objToJsonString: info.args]}];
    [self evaluateJavaScript:[NSString stringWithFormat:@"window._handleMessageFromNative(%@)",json]
           completionHandler:nil];
}

- (void)addJavascriptApi:(DTSDKJsApi *  _Nullable)jsapi{
    
//    jsapi.delegate = self;
    [javaScriptNamespaceInterfaces setObject:jsapi forKey:@""];
}

- (void)addJavascriptApi:(DTSDKJsApi *  _Nullable)jsapi namespace:(NSString *  _Nullable) namespace{
    
    
    if(namespace==nil){
        namespace=@"";
    }
    if(jsapi!=NULL){
//        jsapi.delegate = self;
        [javaScriptNamespaceInterfaces setObject:jsapi forKey:namespace];
    }
}

- (void) addJavascriptObject:(id)object namespace:(NSString *)namespace{
    if(namespace==nil){
        namespace=@"";
    }
    if(object!=NULL){
        [javaScriptNamespaceInterfaces setObject:object forKey:namespace];
    }
}

- (void) removeJavascriptObject:(NSString *)namespace {
    if(namespace==nil){
        namespace=@"";
    }
    [javaScriptNamespaceInterfaces removeObjectForKey:namespace];
}

- (void)customJavascriptDialogLabelTitles:(NSDictionary *)dic{
    if(dic){
        dialogTextDic=dic;
    }
}

- (id)onMessage:(NSDictionary *)msg type:(int)type{
    id ret=nil;
    switch (type) {
        case DSB_API_HASNATIVEMETHOD:
            ret= [self hasNativeMethod:msg]?@1:@0;
            break;
        case DSB_API_CLOSEPAGE:
            [self closePage:msg];
            break;
        case DSB_API_RETURNVALUE:
            ret=[self returnValue:msg];
            break;
        case DSB_API_DSINIT:
            ret=[self dsinit:msg];
            break;
        case DSB_API_DISABLESAFETYALERTBOX:
            [self disableJavascriptDialogBlock:[msg[@"disable"] boolValue]];
            break;
        default:
            break;
    }
    return ret;
}

- (bool) hasNativeMethod:(NSDictionary *) args
{
    NSArray *nameStr=[DTJSBUtil parseNamespace:[args[@"name"]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
    NSString * type= [args[@"type"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
    id JavascriptInterfaceObject= [javaScriptNamespaceInterfaces objectForKey:nameStr[0]];
    if(JavascriptInterfaceObject){
        bool syn=[DTJSBUtil methodByNameArg:1 selName:nameStr[1] class:[JavascriptInterfaceObject class]]!=nil;
        bool asyn=[DTJSBUtil methodByNameArg:2 selName:nameStr[1] class:[JavascriptInterfaceObject class]]!=nil;
        if(([@"all" isEqualToString:type]&&(syn||asyn))
           ||([@"asyn" isEqualToString:type]&&asyn)
           ||([@"syn" isEqualToString:type]&&syn)
           ){
            return true;
        }
    }
    return false;
}

- (id) closePage:(NSDictionary *) args{
    if(javascriptCloseWindowListener){
        javascriptCloseWindowListener();
    }
    return nil;
}

- (id) returnValue:(NSDictionary *) args{
    void (^ completionHandler)(NSString *  _Nullable)= handerMap[args[@"id"]];
    if(completionHandler){
        if(isDebug){
            completionHandler(args[@"data"]);
        }else{
            @try{
                completionHandler(args[@"data"]);
            }@catch (NSException *e){
                NSLog(@"%@",e);
            }
        }
        if([args[@"complete"] boolValue]){
            [handerMap removeObjectForKey:args[@"id"]];
        }
    }
    return nil;
}

- (id) dsinit:(NSDictionary *) args{
    [self dispatchStartupQueue];
    return nil;
}

- (void) disableJavascriptDialogBlock:(bool) disable{
    jsDialogBlock=!disable;
}

- (void)hasJavascriptMethod:(NSString *)handlerName methodExistCallback:(void (^)(bool exist))callback{
    [self callHandler:@"_hasJavascriptMethod" arguments:@[handlerName] completionHandler:^(NSNumber* _Nullable value) {
        callback([value boolValue]);
    }];
}

#pragma mark -- 新增方法
/**
 * refresh
 **/
-(void)refresh{
    dispatch_async(dispatch_get_main_queue(), ^{
        [self callHandler:@"refresh" completionHandler:^(id  _Nullable value) {
            
        }];
    });
}


/**
 * 加载Url
 * @param baseUrl 地址 baseUrl
 * @param clientId clientId
 * @param clientSecret clientSecret
 * @param timestamp timestamp时间戳
 * @param uid 用户id
 **/
-(void)loadbaseUrl:(NSString *)baseUrl
          ClientId:(NSString *)clientId
      clientSecret:(NSString *)clientSecret
       currentTime:(NSInteger)timestamp
               uid:(NSString *)uid{
    
    NSString * type = @"page.taolijin";
    NSString * sign = [self getSignClientId:clientId clientSecret:clientSecret currentTime:timestamp uid:uid type:type];
    NSString * urlstring = [NSString stringWithFormat:@"%@?client_id=%@&sign=%@&timestamp=%ld&uid=%@&type=%@",baseUrl,clientId,sign,timestamp,uid,type];
    [self loadUrl:urlstring];
    
    [ZTYTools sharedTools].clientId = clientId;
    [ZTYTools sharedTools].clientSecret = clientSecret;
    [ZTYTools sharedTools].uid = uid;
}

/**
 * 授权
 * @param clientId clientId
 * @param clientSecret clientSecret
 * @param uid 用户id
 * @param isRelease 是否正式环境
 **/
-(void)signClientId:(NSString *)clientId
      clientSecret:(NSString *)clientSecret
               uid:(NSString *)uid
           environ:(BOOL)isRelease{
    
    NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0];
    NSInteger timestamp=[dat timeIntervalSince1970];
    NSString * type = @"page.taolijin";
//    NSString * baseUrl = @"https://ec-api.thefifthera.com";
//    if (!isRelease) baseUrl = @"https://ec-api-test.thefifthera.com"; //
    
    NSString * baseUrl = @"https://ec-api.thefifthera.com/h5/v1/auth/redirect";
    if (!isRelease) baseUrl = @"https://ec-api-test.thefifthera.com/h5/v1/auth/redirect"; //
    
    NSString * sign = [self getSignClientId:clientId clientSecret:clientSecret currentTime:timestamp uid:uid type:type];
    NSString * urlstring = [NSString stringWithFormat:@"%@?client_id=%@&sign=%@&timestamp=%ld&uid=%@&type=%@",baseUrl,clientId,sign,timestamp,uid,type];
    [self loadUrl:urlstring];
    
    [ZTYTools sharedTools].clientId = clientId;
    [ZTYTools sharedTools].clientSecret = clientSecret;
    [ZTYTools sharedTools].uid = uid;
    [ZTYTools sharedTools].isRelease = isRelease;
    [ZTYTools sharedTools].baseUrl = baseUrl;
    
    
}

-(NSString *)authorityUrl:(NSDictionary *)args environ:(BOOL)isRelease{
    NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0];
    NSInteger timestamp=[dat timeIntervalSince1970];
    
    NSString * baseUrl = @"https://ec-api.thefifthera.com/h5/v1/auth/redirect";
    if (!isRelease) baseUrl = @"https://ec-api-test.thefifthera.com/h5/v1/auth/redirect"; //
    
    
    
    NSString * clientId = [args objectForKey:@"client_id"];
    NSString * clientSecret = [args objectForKey:@"client_secret"];
    NSString * uid = [args objectForKey:@"uid"];
    NSString * token = [args objectForKey:@"token"];
    NSString * type = [args objectForKey:@"type"];
    
    if (clientId.length == 0) {
        [ZTYTools showMessage:@"缺少字段client_id"];
        return @"";
    }
    if (clientSecret.length == 0) {
        [ZTYTools showMessage:@"缺少字段client_secret"];
        return @"";
    }
    
    if (type.length == 0) {
        [ZTYTools showMessage:@"缺少字段type"];
        return @"";
    }
    NSMutableDictionary * dict = [NSMutableDictionary dictionaryWithDictionary:args];
    [dict setObject:@(timestamp) forKey:@"timestamp"];
//    NSString * sign = [self getSignParam:dict];//[self getSignClientId:clientId clientSecret:clientSecret currentTime:timestamp uid:uid type:type token:token]; // [self getSignParam:dict];//
    
//    NSString * urlstring = [NSString stringWithFormat:@"%@?client_id=%@&sign=%@&timestamp=%ld&uid=%@&type=%@",baseUrl,clientId,sign,timestamp,uid,type];
    
    NSArray *keys = [dict allKeys];
    NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        NSComparisonResult result = [obj1 compare:obj2 options:NSLiteralSearch];
        return result == NSOrderedDescending;
    }];
    
    
    NSMutableString *orderStringParams = [[NSMutableString alloc] init];
    NSMutableString *urlstr = [[NSMutableString alloc] init];
    [orderStringParams appendString:[dict objectForKey:@"client_secret"]];
    for (int i = 0; i < [sortedArray count]; i++) {
        NSString *categoryId = sortedArray[i];
        NSString * value = [NSString stringWithFormat:@"%@",[dict objectForKey:categoryId]];
        if ([categoryId isEqualToString:@"client_secret"]) {
            continue;
        }
        [orderStringParams appendString:[NSString stringWithFormat:@"%@%@",categoryId,value]];
        
        [urlstr appendString:[NSString stringWithFormat:@"%@=%@", categoryId, value]];
        
        if (i != ([sortedArray count] - 1)){
            [urlstr appendString:@"&"];
        }
    }
    
    
    [orderStringParams appendString:[dict objectForKey:@"client_secret"]];
    //    NSLog(@"orderStringParams==>%@",orderStringParams);
    NSString * encodestr = [[ZTYTools md5:orderStringParams] uppercaseString];

    [ZTYTools sharedTools].clientId = clientId;
    [ZTYTools sharedTools].clientSecret = clientSecret;
    
    [ZTYTools sharedTools].isRelease = isRelease;
    [ZTYTools sharedTools].baseUrl = baseUrl;
    if (uid == nil || uid.length == 0) {
        NSString * staticUrl = @"";
        if (isRelease) {
            staticUrl = @"https://static.thefifthera.com";
            return [NSString stringWithFormat:@"https://static.thefifthera.com/h5/unlogin/index.html?client_id=%@",clientId];
        }else{
            return [NSString stringWithFormat:@"https://static-test.thefifthera.com/h5/unlogin/index.html?client_id=%@",clientId];
        }
    }
    [ZTYTools sharedTools].uid = uid;
    NSString * urlstring = [NSString stringWithFormat:@"%@?%@&sign=%@",baseUrl,urlstr,encodestr];
    
    
    
    return urlstring;
}

-(NSString *)getSignParam:(NSDictionary *)params{
    
    NSArray *keys = [params allKeys];
    NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        NSComparisonResult result = [obj1 compare:obj2 options:NSLiteralSearch];
        return result == NSOrderedDescending;
    }];
    
    
    NSMutableString *orderStringParams = [[NSMutableString alloc] init];
    [orderStringParams appendString:[params objectForKey:@"client_secret"]];
    for (int i = 0; i < [sortedArray count]; i++) {
        NSString *categoryId = sortedArray[i];
        NSString * value = [NSString stringWithFormat:@"%@",[params objectForKey:categoryId]];
        if ([categoryId isEqualToString:@"sign"] || [categoryId isEqualToString:@"sign_type"]|| [categoryId isEqualToString:@"client_secret"] || value.length == 0) {
            continue;
        }
        
        
        [orderStringParams appendString:[NSString stringWithFormat:@"%@%@",categoryId,value]];
        
//        if (i != ([sortedArray count] - 1)){
//            [orderStringParams appendString:@""];
//        }
    }
    
    
    [orderStringParams appendString:[params objectForKey:@"client_secret"]];
//    NSLog(@"orderStringParams==>%@",orderStringParams);
    NSString * encodestr = [[ZTYTools md5:orderStringParams] uppercaseString];
//    NSLog(@"encodestr==>%@",encodestr);
    return encodestr;
}

-(NSString *)getSignClientId:(NSString *)clientId clientSecret:(NSString *)clientSecret currentTime:(NSInteger)time uid:(NSString *)uid type:(NSString *)type{

    NSString * str = [NSString stringWithFormat:@"%@client_id%@timestamp%ldtype%@uid%@%@",clientSecret,clientId,time,type,uid,clientSecret];
    NSString * encodestr = [[ZTYTools md5:str] uppercaseString];

    return encodestr;

}

-(NSString *)getSignClientId:(NSString *)clientId clientSecret:(NSString *)clientSecret currentTime:(NSInteger)time uid:(NSString *)uid type:(NSString *)type token:(NSString *)token{
    
    NSString * str = [NSString stringWithFormat:@"%@client_id%@timestamp%ldtype%@uid%@%@",clientSecret,clientId,time,type,uid,clientSecret];
    if (token.length > 0) {
        str = [NSString stringWithFormat:@"%@client_id%@timestamp%ldtoken%@type%@uid%@%@",clientSecret,clientId,time,token,type,uid,clientSecret];
    }
    
//    NSLog(@"str====>%@",str);
    NSString * encodestr = [[ZTYTools md5:str] uppercaseString];
    
    return encodestr;
    
}

-(void)loadTaobaoAuthUrl{
    NSString * url = [NSString stringWithFormat:@"%@%@%@",@"https://ec-share.thefifthera.com",@"/h5/v1/taobaooauth/",[ZTYTools sharedTools].clientId];
    if (![ZTYTools sharedTools].isRelease) {
        url = [NSString stringWithFormat:@"%@%@%@",@"https://ec-share-test.thefifthera.com",@"/h5/v1/taobaooauth/",[ZTYTools sharedTools].clientId];
    }
    [self loadUrl:url];
}

-(void)dealloc{
    NSLog(@"delloc");
}

//-(NSString *)getAuthurl{
//    return [DTShareImgView share].authUrl;
//}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

@end
